/**
 * @file singleton.cc
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-03-27
 *
 * @copyright Copyright (c) 2022
 *
 */

#include <iostream>
#include <memory>
#include <mutex>
using namespace std;
#define v2_1

/**
 * @brief 乞丐版单例模式
 * 1 构造函数私有化
 * 2 静态成员函数static
 * 3 静态数据成员static
 */

#ifdef v1
class Singleton
{
  public:
    static Singleton *getInstance()
    {
        if (_pInstance == nullptr) {
            return new Singleton();
        }
        return _pInstance;
    }

  private:
    Singleton();
    static Singleton *_pInstance;
};

Singleton *Singleton::_pInstance;
#endif

/**
 * @brief 锁+内部类单例模式
 * 1 要双重判空
 * 2 析构私有化
 * 3 内部类析构调用单例析构，析构完记得置空指针
 */
#ifdef v2
class Singleton
{
  public:
    static Singleton *getInstance()
    {
        if (nullptr == _pInstance) {
            lock_guard<mutex> lock(_mutex);
            if (nullptr == _pInstance) {
                return new Singleton();
            }
            return _pInstance;
        }
    }

  private:
    Singleton();
    ~Singleton();
    class Grabo
    {
      public:
        ~Grabo()
        {
            if (Singleton::_pInstance) {
                delete Singleton::_pInstance;
            }
            Singleton::_pInstance == nullptr;
        }
    };
    static Grabo gra;
    static Singleton *_pInstance;
    static mutex _mutex;
};

Singleton *Singleton::_pInstance;
mutex Singleton::_mutex;
Singleton::Grabo Singleton::gra = Grabo();
#endif

/**
 * @brief 锁+智能指针 单例模式
 * 1 双重校验锁
 * 2 析构不能私有化
 */

#ifdef v2_1
class Singleton
{
  public:
    using PTR = shared_ptr<Singleton>;
    static PTR getInstance()
    {
        if (nullptr == _pInstance) {
            lock_guard<mutex> lock(_mutex);
            if (nullptr == _pInstance) {
                return PTR(new Singleton());
            }
        }
        return _pInstance;
    }
    ~Singleton();

  private:
    Singleton();
    static PTR _pInstance;
    static mutex _mutex;
};
Singleton::PTR Singleton::_pInstance;
mutex Singleton::_mutex;

#endif

